package crypto

import (
	"bytes"
	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/armor"
	"io/ioutil"
	"math/big"

	"crypto/dsa"
	"crypto/rand"
	"crypto/rsa"
)

func NewDs() *ds {
	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		panic(err)
	}

	parameters := new(dsa.Parameters)
	err = dsa.GenerateParameters(parameters, rand.Reader, dsa.L1024N160)
	if err != nil {
		panic(err)
	}

	dsaPrivateKey := new(dsa.PrivateKey)
	dsaPrivateKey.Parameters = *parameters
	err = dsa.GenerateKey(dsaPrivateKey, rand.Reader)
	if err != nil {
		panic(err)
	}

	return &ds{
		privateKey:    privateKey,
		publicKey:     &privateKey.PublicKey,
		dsaPrivateKey: dsaPrivateKey,
		dsaPublicKey:  &dsaPrivateKey.PublicKey,
	}
}

type ds struct {
	privateKey    *rsa.PrivateKey
	publicKey     *rsa.PublicKey
	dsaPrivateKey *dsa.PrivateKey
	dsaPublicKey  *dsa.PublicKey
}

// Rsa
// publicKey
// privateKey
func (r *ds) Rsa(source []byte) []byte {
	encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, r.publicKey, source)
	if err != nil {
		panic(err)
	}

	return encrypted
}
func (r *ds) RsaDecrypt(source []byte) []byte {
	decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, r.privateKey, source)
	if err != nil {
		panic(err)
	}

	return decrypted
}

// Dsa
// dsaPrivateKey
func (r *ds) Dsa(source []byte) (*big.Int, *big.Int) {
	hashed := NewHash().Sha1(source)

	r1, s1, err := dsa.Sign(rand.Reader, r.dsaPrivateKey, hashed)
	if err != nil {
		panic(err)
	}

	return r1, s1
}
func (r *ds) DsaVerify(source []byte, r1, s1 *big.Int) bool {
	hashed := NewHash().Sha1(source)

	return dsa.Verify(r.dsaPublicKey, hashed, r1, s1)
}

// Openpgp
func (r *ds) Openpgp(message []byte) []byte {
	var encrypted bytes.Buffer

	entity, err := openpgp.NewEntity("BeeSoft", "BeeSoft", "beherochuling@163.com", nil)
	if err != nil {
		panic(err)
	}

	writer, err := armor.Encode(&encrypted, openpgp.SignatureType, nil)
	if err != nil {
		panic(err)
	}

	writer, err = openpgp.Encrypt(writer, []*openpgp.Entity{entity}, nil, nil, nil)
	if err != nil {
		panic(err)
	}

	_, err = writer.Write(message)
	if err != nil {
		panic(err)
	}

	err = writer.Close()
	if err != nil {
		panic(err)
	}

	return encrypted.Bytes()
}
func (r *ds) OpenpgpDecrypt(message []byte) []byte {
	var encrypted bytes.Buffer

	encryptedBlock, err := armor.Decode(&encrypted)
	if err != nil {
		panic(err)
	}

	messageDetails, err := openpgp.ReadMessage(encryptedBlock.Body, nil, func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
		return nil, nil
	}, nil)
	if err != nil {
		panic(err)
	}

	decrypted, err := ioutil.ReadAll(messageDetails.UnverifiedBody)
	if err != nil {
		panic(err)
	}

	return decrypted
}
func (r *ds) openpgpMore() {
	// openpgp.SignatureType
	// openpgp.PrivateKeyType
	// openpgp.PublicKeyType
	// openpgp.ReadKeyRing()
	// openpgp.CheckDetachedSignature()
	// openpgp.DetachSign()
	// openpgp.DetachSignText()
	// openpgp.ReadArmoredKeyRing()
	// openpgp.CheckArmoredDetachedSignature()
	// openpgp.ArmoredDetachSign()
	// openpgp.ArmoredDetachSignText()

	// openpgp.Sign()
	// openpgp.NewCanonicalTextHash()
	// openpgp.SymmetricallyEncrypt()
	// openpgp.ReadEntity()
}
